/****************************************************************************************************************************
 * Copyright © dimon.chen 2024-2034 All right reserved. GPL2.0 License 
 * 文件名   :   led.s
 * 作者     :   dimon.chen
 * 版本     :   V1.0
 * 描述     :   正点原子I.MX6U ALPHA/Mini 开发板Linuxa之ARM裸机开发
 *              裸机实验1 汇编点灯
 *              使用汇编语言来点亮开发板的LED灯，学习和掌握如何使用汇编
 *              完成对 I.MX6U 处理器的 GPIO 初始化
 * 其它     :   无
 * 日期     :   2024-04-26 19:26 
 * 历史     ：  出版本V1.0 2024/04/26 dimon.chen 创建
 ****************************************************************************************************************************/


    /*
     * I.MX6U 使用GPIO的步骤为如下几步
     * 1. 使能 GPIO 外设时钟
     * 2. 设置 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 ，设置 IO 复用为 GPIO 
     * 3. 设置 IOMUXC_SW_PAD_CT_L_PAD_GPIO1_IO03 设置芯片 IO 管脚的电气属性，如压摆率，速率
     * 4. 在前3步设置IO的复用模式，IO的管脚的电气特性后。设置GPIO的输出电平，高电平，第电平
     */

    

    // !! I.MX6U 一共有6组GPIO !!
    //
    @ I.MUX6U的GPIO一共有5组：GPIO1，GPIO2，GPIO2，GPIO4 和 GPIO5
    @ 其中GPIO1有32个IO
    @ GPIO2有22个IO
    @ GPIO3有29个IO
    @ GPIO4有29个IO
    @ GPIO5最少，只有12个IO
    @ 这样一共 124 个GPIO
    @
    @ 如果想要看每个 IO 能复用成什么外设，可以直接查阅 《I.MX6U参考手册》的第4章 Chapter 4:
    @ External Signals and Pin Multipexing。


    // !! CCM: Clock Control Module !!
    // !! CCGR0: CCM Clock Gating Register 0 !!
    //
    // 
    @ 设置 I.MX6U 芯片，使能 GPIO 外设时钟，
    @《I.MX6U 参考手册》第18张时钟管理 CCM (Clock Controller Module) 章节有说明 I.MX6U 的CCM寄存器配置来
    @ 启用对应的外设时钟。
    @ I.MX6U 有 CCM_CCGR0 ~ CCM_CCGR6 共7个时钟寄存器，这7个 CCM_CCGRx 寄存器控制了所有的 I.MX6U 芯片的外设
    @ 的时钟开启和关闭。
    @ 为了简单和方便起见，我们在 led.s 汇编LED点灯程序中直接使能 I.MX6U 的所有外设时钟，就是设置 CCM_CCGR0~CCM_CCGR6
    @ 的值为 0xFFFF_FFFF
    @
    @ CCM_CCGR0 寄存器的地址，查阅《I.MX6U参考手册》第18章 Clock Controller Module 一节，可以找到CCM_CCGR0-6寄存器的地址:
    @       CCM_CCGR0 地址 = 0X020C_4068
    @       CCM_CCGR1 地址 = 0X020C_406C
    @       CCM_CCGR2 地址 = 0X020C_4070
    @       CCM_CCGR3 地址 = 0X020C_4074
    @       CCM_CCGR4 地址 = 0X020C_4078
    @       CCM_CCGR5 地址 = 0X020C_407C
    @       CCM_CCGR5 地址 = 0X020C_4080



/* 全局标号 */
.global _start  


/*
 * 描述：_start 函数，程序从此函数开始执行此函数完成时钟功能
 *      GPIO初始化，最终控制 GPIO 输出低电平来点亮LED灯。
 */
_start:
    /* 使能所有 I.MX6U 芯片外设时钟 */
    ldr r0, =0x020C4068     @CCM_CCGR0
    ldr r1, =0xFFFFFFFF     @将0xFFFFFFFF写入CCM_CCGR0写入的数据
    str r1, [r0]

    ldr r0, =0x020C406C     @CCM_CCGR1
    str r1, [r0]

    ldr r0, =0x020C4070     @CCM_CCGR2
    str r1, [r0]

    ldr r0, =0x020C4074     @CCM_CCGR3
    str r1, [r0]

    ldr r0, =0x020C4078     @CCM_CCGR4
    str r1, [r0]

    ldr r0, =0x020C407C     @CCM_CCGR5
    str r1, [r0]

    ldr r0, =0x020C4080     @CCM_CCGR6
    str r1, [r0]


    /* 配置 GPIO1_IO03 PIN 复用为GPIO，也就是设置
     * IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = 5
     * 寄存器地址为 0X020E_0068
     */
    ldr r0, =0x020E0068     @IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03
    ldr r1, =0x5            @将0x5写入到 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 中
    str r1, [r0]



    /* 配置GPIO1_IO03 的电气属性（上下拉，偏摆率），也就是寄存器
     * IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03
     * IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 寄存器地址为 0X020E_02F4
     *
     *
     * bit0：          SRE压摆率, 值：0 低速率
     * bit2-1:         Resverd保留未使用, NA      
     * bit5-3:         DSE, Drive Stength 驱动能力, 值：110, R0/6 数值越小，驱动能里越强
     * bit7-6:         Speed 速率， 值: 10，100MHz
     * bit 10-8:       Resverd保留未使用，值: NA 
     * bit11:          ODE, Open Drawn Enable开漏输出，值: 0，关闭开路输出
     * bit12:          PKE,Pull/Keeper Enable 上拉/保持使能,值：1,使能 Pull/Keeper
     * bit13:          PUE,Pull/Keeper 上拉/保持选择     值: 0, 选择Keeper
     * bit15-14:       PUS,Pull Select 设置上下拉电阻   值: 00, 100K Ohm Pull Down
     * bit16:          hyst磁滞（输入有效), 值：0, Hystersis Disable 磁滞关闭, 关闭Hys
     * bit31-17:       保留未使用 
     */

    ldr r0, =0x020E02F4
    ldr r1, =0x10B0
    str r1, [r0]


    /* 设置 GPIO
     * 设置 GPIO1_GDIR寄存器，设置 设置 GPIO1_IO03 为输出
     * GPIO1_GDIR 寄存器地址为 0X209_C004，设置 GPIO1_IO03 寄存器 bit3为1
     * 也就是 GPIO1_IO03为输出
     */
    ldr r0, =0X0209C004  @GPIO1_GDIR
    ldr r1, =0x8         @bit3，从0开始例如GPIO1_IO00,GPIO1_IO01,GPIO1_IO02,GPIO1_IO03
    str r1, [r0]


    /* 打开LED，也就是设置GPIO1_IO03为0，也就是输出低电平，
     * 根据正点原子I.M6ULL Mini 开发板电路原理图，GPIO1_IO03 输出低电平
     * LED灯就打开.
     * GPIO1_DR 寄存器的地址为 0X0209_C000
     * GPIOQ_DR bit3 设置为0，输出低电平
     */
    ldr r0, =0x0209C000
    ldr r1, =0x0
    str r1, [r0]


    @在汇编程序的最后放置一个死循环，让程序一直在这里执行。
    @如果防止最后的这个死循环，当程序执行完上面的汇编指令之后，就不知道接下来应该执行什么指令了，
    @就会有异常
loop:
    b loop
